package org.weasel.data;

import java.sql.Time;
import java.util.ArrayList;
import java.util.List;

import org.jdom.Element;
import org.weasel.business.Company;
import org.weasel.business.Developer;
import org.weasel.business.Iteration;
import org.weasel.business.Project;
import org.weasel.business.Release;
import org.weasel.business.Task;
import org.weasel.business.Unscheduled;
import org.weasel.business.UserStory;

@SuppressWarnings("unchecked")
public class XMLLoader {

	private XMLManager xmlMan;
	public XMLLoader(){
	}
	
	/**
	 * Loads the Company from the XML file specified by the path
	 * @param path = XMLFile to parse
	 * @return
	 * @throws Exception
	 */
	
	public Company load(String path) throws Exception{
		xmlMan = new XMLManager(path);
//		&& XMLValidator.getInstance().isValidXMLFile(path)
		if(new FileManager().existsFile(path)) {
			String companyName = xmlMan.getRootElement().getChildText("companyname");
			
			Element developersEl = xmlMan.getRootElement().getChild("developers");
			List<Element> developerElList = developersEl.getChildren();
			ArrayList<Developer> developers = new ArrayList<Developer>();
			for (Element element : developerElList) {
				developers.add(createDeveloperObject(element));
			}
			
			Element projectsEl = xmlMan.getElementByQuery("/descendant::projects");
			List<Element> projectsElList = projectsEl.getChildren();
			ArrayList<Project> projects = new ArrayList<Project>();
			for (Element element : projectsElList) {
				projects.add(createProjectObject(element));
			}
			return new Company(companyName,projects,developers);
		} else {
			return new Company("Weasel",null,null);
		}
	}

	/**
	 * Utility method to parse a project object out of the given
	 * JDOM Element
	 * @param projectEl
	 * @return
	 * @throws Exception
	 */
	private Project createProjectObject(Element projectEl) throws Exception{
		//		add basic elements
		String id = projectEl.getChildText("id");
		String name = projectEl.getChildText("name");
		String notes = projectEl.getChildText("notes");
		String startDate = projectEl.getChildText("startDate");
		int iterationDays;
		try {
			iterationDays = Integer.parseInt(projectEl.getChildText("iterationDays"));
		} catch (NumberFormatException e) {
			System.out.println(e.getMessage());
			//set standard of 6 days
			iterationDays = 6;
		}
		
		//load the developers
		Element developersEl = projectEl.getChild("developers");
		List<Element> developerElList = developersEl.getChildren();
		ArrayList<Developer> developers = new ArrayList<Developer>();
		for (Element element : developerElList) {
			developers.add(getDeveloperObject(element));
		}
		
		//load the releases
		Element releasesEl = projectEl.getChild("releases");
		List<Element> releaseElList = releasesEl.getChildren();
		ArrayList<Release> releases = new ArrayList<Release>();
		for (Element element : releaseElList) {
			releases.add(createReleaseObject(element));
		}
		
		//load the unscheduled area
		Element unscheduledEl = projectEl.getChild("unscheduled");
		Unscheduled unscheduled = createUnscheduledObject(unscheduledEl);

		return new Project(id,name,developers,releases,unscheduled, notes, startDate, iterationDays);
	}

	/**
	 * Utility method to parse a release object out of the given
	 * JDOM Element
	 * @param releaseEl
	 * @return
	 * @throws Exception
	 */
	private Release createReleaseObject(Element releaseEl) throws Exception {
		String id = releaseEl.getChildText("id");
		String name = releaseEl.getChildText("name");
		String notes = releaseEl.getChildText("notes");
		
		
		//load the iterations of this release
//		Element iterationsEl = xmlMan.getElementByQuery("/descendant::*[id=\"" + id + "\"]/iterations[position()=1]");
		Element iterationsEl = releaseEl.getChild("iterations");
		List<Element> iterationElList = iterationsEl.getChildren();
		ArrayList<Iteration> iterations = new ArrayList<Iteration>();
		for (Element element : iterationElList) {
			iterations.add(createIterationObject(element));
		}
		
		//load the unscheduled area of this release
		Element unscheduledEl = releaseEl.getChild("unscheduled");
		Unscheduled unscheduled = createUnscheduledObject(unscheduledEl);
		
		return new Release(id,name,iterations,unscheduled, notes);
	}

	/**
	 * Utility method to parse a unscheduled object out of the given
	 * JDOM Element
	 * @param unscheduledEl
	 * @return
	 * @throws Exception
	 */
	private Unscheduled createUnscheduledObject(Element unscheduledEl) throws Exception {
		String id = unscheduledEl.getChildText("id");
		
		//load the associated userstories
		Element userstoriesEl = unscheduledEl.getChild("userstories");
		List<Element> userstoriesElList = userstoriesEl.getChildren();
		ArrayList<UserStory> userstories = new ArrayList<UserStory>();
		for (Element element : userstoriesElList) {
			userstories.add(createUserStoryObject(element));
		}
		
		return new Unscheduled(id,userstories);
	}

	/**
	 * Utility method to parse a iteration object out of the given
	 * JDOM Element
	 * @param iterationEl
	 * @return
	 * @throws Exception
	 */
	private Iteration createIterationObject(Element iterationEl) throws Exception {
		String id = iterationEl.getChildText("id");
		String name = iterationEl.getChildText("name");
		String notes = iterationEl.getChildText("notes");
		
//		Element userstoriesEl = xmlMan.getElementByQuery("/descendant::*[id=\"" + id + "\"]/userstories[position()=1]");
		Element userstoriesEl = iterationEl.getChild("userstories");
		List<Element> userstoryElList = userstoriesEl.getChildren();
		ArrayList<UserStory> userstories = new ArrayList<UserStory>();
		for (Element element : userstoryElList) {
			userstories.add(createUserStoryObject(element));
		}
		
		
		return new Iteration(id,name,userstories, notes);
	}

	/**
	 * Utility method to parse a userstory object out of the given
	 * JDOM Element
	 * @param storyEl
	 * @return
	 * @throws Exception
	 */
	private UserStory createUserStoryObject(Element storyEl) throws Exception {
		String id = storyEl.getChildText("id");
		String name = storyEl.getChildText("name");
		String description = storyEl.getChildText("description");
		String generatedDate = storyEl.getChildText("generatedDate");
		String finishedDate = storyEl.getChildText("finishedDate");
		int businessValue = Integer.parseInt(storyEl.getChildText("businessValue"));
		Time estimatedTime = Time.valueOf(storyEl.getChildText("estimatedTime"));
		Time usedTime = Time.valueOf(storyEl.getChildText("usedTime"));
		int risk = Integer.parseInt(storyEl.getChildText("risk"));		
		boolean experimental = Boolean.parseBoolean(storyEl.getChildText("experimental"));
		
		Element tasksEl = storyEl.getChild("tasks");
		List<Element> taskElList = tasksEl.getChildren();
		ArrayList<Task> tasks = new ArrayList<Task>();
		for (Element element : taskElList) {
			tasks.add(createTaskObject(element));
		}
		
		Element developersEl = storyEl.getChild("developers");
		List<Element> developerElList = developersEl.getChildren();
		ArrayList<Developer> developers = new ArrayList<Developer>();
		for (Element element : developerElList) {
			developers.add(getDeveloperObject(element));
		}
		
		return new UserStory(id,name,generatedDate, finishedDate, description,estimatedTime,usedTime,risk,businessValue,experimental,developers, tasks);
	}

	/**
	 * Utility method to parse a developer object out of the given
	 * JDOM Element; specifically this method is used to parse out the general
	 * developers of the company. For the other developers stored in the different
	 * projects/userstories, the method getDeveloperObject(...) is used.
	 * @param element
	 * @return
	 */
	private Developer createDeveloperObject(Element element) {
		String developerId = element.getChildText("id");
		String developerName = element.getChildText("name");
		String developerEmail = element.getChildText("email");
		String developerPos = element.getChildText("position");
		
		return new Developer(developerId,developerName, developerPos, developerEmail);
	}
	
	/**
	 * Utility method to parse a developer object out of the given
	 * JDOM Element
	 * Used in places, where we only have the id of the developer and not all
	 * the information such as name, email, etc...
	 * @param developerEl
	 * @return
	 * @throws Exception
	 */
	private Developer getDeveloperObject(Element developerEl) throws Exception {
		String developerId = developerEl.getText();
		Element devEl = xmlMan.getElementByQuery("/descendant::developers[position()=1]/developer[id=\"" + developerId + "\"]");
		
		return createDeveloperObject(devEl);
	}

	/**
	 * Utility method to parse a task object out of the given
	 * JDOM Element
	 * @param taskEl
	 * @return
	 */
	private Task createTaskObject(Element taskEl) {
		String id = taskEl.getChildText("id");
		String description = taskEl.getChildText("description");
		boolean completed = Boolean.parseBoolean(taskEl.getChildText("isCompleted"));
		
		return new Task(id,description,completed);
	}
}
